package com.whcoding.test.common;


import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ReflectUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import org.apache.commons.beanutils.BeanMap;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
 * @program: spring-boot-learning
 * @description: 使用这个进行转化
 * @author: whcoding
 * @create: 2022-04-01 18:26
 **/
public class BeanUtil {

	public BeanUtil() {
	}
	/**
	 * 将Bean复制到Map里面去。
	 *
	 * @param bean
	 * @param map
	 */
	public static void bean2map(Object bean, Map map) {
		BeanMap beanMap = new BeanMap(bean);
		for (Object key : beanMap.keySet()) {
			Object value = beanMap.get(key);
			if (value == null)
				continue;
			map.put(key.toString(), value);
		}
	}

	public static void bean2map2(Object bean, Map map) {
		BeanMap beanMap = new BeanMap(bean);
		Iterator var3 = beanMap.keySet().iterator();

		while (var3.hasNext()) {
			Object key = var3.next();
			Object value = beanMap.get(key);
			if (value != null) {
				map.put(key.toString(), value);
			}
		}

		map.remove("class");
	}


	/**
	 * Map转换为Java Bean 方法一
	 *
	 * @param map
	 *              待转换的Map
	 * @param object
	 *              Java Bean
	 * @return java.lang.Object
	 * @since v1.0.0
	 */
	public static Object map2Bean(Map map,Object object){
		if(map == null || object == null){
			return null;
		}
		try {
			BeanInfo beanInfo = Introspector.getBeanInfo(object.getClass());
			PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();

			for (PropertyDescriptor property : propertyDescriptors) {
				String key = property.getName();
				if (map.containsKey(key)) {
					Object value = map.get(key);
					// 得到property对应的setter方法
					Method setter = property.getWriteMethod();
					setter.invoke(object, value);
				}
			}
		} catch (IntrospectionException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
		return object;
	}



	/**
	 * 单个类转换
	 *
	 * @param sourceObj 数据源
	 * @param targetClass 目标源 [转为某个类]
	 * @param <T>
	 * @return
	 */
	public static <T> T convertBean(Object sourceObj, Class<T> targetClass) {
		if (sourceObj == null || targetClass == null) {
			return null;
		}
		T targetObj = null;
		try {
			targetObj = targetClass.newInstance();
		} catch (InstantiationException | IllegalAccessException e) {
			return null;
		}
		BeanUtils.copyProperties(sourceObj, targetObj);
		return targetObj;
	}


	/**
	 * List集合之间的对象属性赋值
	 * @param input 输入集合
	 * @param clzz  输出集合类型
	 * @param <E>   输入集合类型
	 * @param <T>   输出集合类型
	 * @return 返回集合
	 */
	public static <E, T> List<T> convertList2List(List<E> input, Class<T> clzz) {
		List<T> output = Lists.newArrayList();
		if (CollectionUtils.isNotEmpty(input)) {
			for (E source : input) {
				T target = BeanUtils.instantiateClass(clzz);
				BeanUtils.copyProperties(source, target);
				output.add(target);
			}
		}
		return output;
	}

	/**
	 * List之间转换
	 *
	 * @param sourceList
	 * @param targetClass
	 * @param <T>
	 * @return
	 */
	public static <T> List<T> convertList2List2(List<?> sourceList, Class<T> targetClass) {
		if (org.springframework.util.CollectionUtils.isEmpty(sourceList) || targetClass == null) {
			return Collections.emptyList();
		}
		return sourceList.stream().map(sourceObj -> convertBean(sourceObj, targetClass)).collect(Collectors.toList());
	}

	/**
	 * List 之间进行Copy
	 * @param list
	 * @param <T>
	 * @return
	 */
	public static <T> List copyList(List<T> list) {
		if (org.springframework.util.CollectionUtils.isEmpty(list)) {
			return new ArrayList();
		}
		return JSON.parseArray(JSON.toJSONString(list), list.get(0).getClass());
	}

	/**
	 * Map 进行copy
	 *
	 * @param map
	 * @return
	 */
	public static Map<String, Object> copyMap(Map map) {
		return JSON.parseObject(JSON.toJSONString(map));
	}


	/**
	 * 复制sour里属性不为空的值到obje为空的属性
	 *
	 * @param obje    目标实体类
	 * @param sour    源实体类
	 * @param isCover 是否保留obje类里不为null的属性值(true为保留源值，属性为null则赋值)
	 * @return obje
	 */
	public static Object beanCopy(Object sour,Object obje, boolean isCover) {
		Field[] fields = sour.getClass().getDeclaredFields();
		for (int i = 0, j = fields.length; i < j; i++) {
			String propertyName = fields[i].getName();
			Object propertyValue = getProperty(sour, propertyName);
			if (isCover) {
				if (getProperty(obje, propertyName) == null && propertyValue != null) {
					Object setProperty = setProperty(obje, propertyName, propertyValue);
				}
			} else {
				Object setProperty = setProperty(obje, propertyName, propertyValue);
			}
		}
		return obje;
	}

	/**
	 * 复制sour里属性不为空的值到obj里并相加
	 *
	 * @param obj     目标实体类
	 * @param sour    源实体类
	 * @param isCover
	 * @return obj
	 */
	public static Object beanCopyAndAdd(Object obj, Object sour, boolean isCover) {
		Field[] fields = sour.getClass().getDeclaredFields();
		for (int i = 0, j = fields.length; i < j; i++) {
			String propertyName = fields[i].getName();
			Object sourPropertyValue = getProperty(sour, propertyName);
			Object objPropertyValue = getProperty(obj, propertyName);
			if (isCover) {
				if (objPropertyValue == null && sourPropertyValue != null) {
					Object setProperty = setProperty(obj, propertyName, sourPropertyValue);
				} else if (objPropertyValue != null && sourPropertyValue == null) {
					Object setProperty = setProperty(obj, propertyName, objPropertyValue);
				} else if (objPropertyValue != null && sourPropertyValue != null) {
					Object setProperty = setProperty(obj, propertyName, ((int) sourPropertyValue) + (int) objPropertyValue);
				}
			}

		}
		return obj;
	}

	/**
	 * 得到值
	 *
	 * @param bean
	 * @param propertyName
	 * @return
	 */
	private static Object getProperty(Object bean, String propertyName) {
		Class clazz = bean.getClass();
		try {
			Field field = clazz.getDeclaredField(propertyName);
			Method method = clazz.getDeclaredMethod(getGetterName(field.getName()));
			return method.invoke(bean);
		} catch (Exception e) {
		}
		return null;
	}

	/**
	 * 给bean赋值
	 *
	 * @param bean
	 * @param propertyName
	 * @param value
	 * @return
	 */
	private static Object setProperty(Object bean, String propertyName, Object value) {
		Class clazz = bean.getClass();
		try {
			Field field = clazz.getDeclaredField(propertyName);
			Method method = clazz.getDeclaredMethod(getSetterName(field.getName()), field.getType());
			return method.invoke(bean, value);
		} catch (Exception e) {
		}
		return null;
	}

	/**
	 * 根据变量名得到get方法
	 *
	 * @param propertyName
	 * @return
	 */
	private static String getGetterName(String propertyName) {
		String method = "get" + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1);
		return method;
	}

	/**
	 * 得到setter方法
	 *
	 * @param propertyName 变量名
	 * @return
	 */
	private static String getSetterName(String propertyName) {
		String method = "set" + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1);
		return method;
	}

	/**
	 *
	 * @param list
	 * @param keyExtractor
	 * @param <T>
	 * @return
	 */
	public static <T> List<T> distinctListByKey(List<T> list, Function<? super T, Object> keyExtractor) {
		return list.stream().filter(distinctByKey(keyExtractor)).collect(Collectors.toList());
	}

	private static <T> Predicate<T> distinctByKey(Function<? super T, Object> keyExtractor) {
		Map<Object, Boolean> seen = new ConcurrentHashMap();
		return (object) -> {
			return seen.putIfAbsent(keyExtractor.apply(object), Boolean.TRUE) == null;
		};
	}

	public static String[] getNullPropertyNames(Object source) {
		BeanWrapper src = new BeanWrapperImpl(source);
		PropertyDescriptor[] pds = src.getPropertyDescriptors();
		Set<String> emptyNames = new HashSet();
		PropertyDescriptor[] var4 = pds;
		int var5 = pds.length;

		for (int var6 = 0; var6 < var5; ++var6) {
			PropertyDescriptor pd = var4[var6];
			Object srcValue = src.getPropertyValue(pd.getName());
			if (srcValue == null) {
				emptyNames.add(pd.getName());
			}
		}
		String[] result = new String[emptyNames.size()];
		return emptyNames.toArray(result);
	}

	/**
	 * 将List对象转换成Map(无嵌套)
	 *
	 * @param param
	 * @param fieldName 需要 reduce 的属性名
	 * @return
	 */
	public static <T> List<Map<String, Object>> flatList(List<T> param, List<String> fieldName) {
		List<Map<String, Object>> result = new ArrayList<>();
		for (T t : param) {
			Map<String, Object> map = flatSingle(t, fieldName);
			result.add(map);
		}
		return result;

	}

	/**
	 * 将单个对象转换成Map(无嵌套)
	 *
	 * @param obj
	 * @param fieldName 需要 reduce 的属性名
	 * @return
	 */
	public static Map<String, Object> flatSingle(Object obj, List<String> fieldName) {
		Map<String, Object> result = MapUtil.newHashMap(32);
		Field[] fields = ReflectUtil.getFields(obj.getClass());
		for (Field field : fields) {
			if (fieldName.contains(field.getName())) {
				JSONObject jsonObject;
				Object value = ReflectUtil.getFieldValue(obj, field);
				if (value instanceof String) {
					jsonObject = JSON.parseObject((String) value);
				} else {
					jsonObject = JSONObject.parseObject(JSON.toJSONString(value));
				}
				for (String key : jsonObject.keySet()) {
					result.put(key, jsonObject.getString(key));
				}
			}
			result.put(field.getName(), ReflectUtil.getFieldValue(obj, field));
		}
		return result;

	}

	/**
	 * 将list转为Map
	 * @param list
	 * @param func
	 * @param <K>
	 * @param <V>
	 * @return
	 */
	public static <K, V> Map<K, List<V>> toMapList(List<V> list, Function<V, K> func) {
		return list.stream().collect(Collectors.groupingBy(func));
	}


}
